﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace CPA
{
    // Warning: Witchcraft Lives Within
    class level
    {
        Texture2D[] water = new Texture2D[2],
            ground = new Texture2D[1],
            grass = new Texture2D[1],
            stone = new Texture2D[1],
            brick = new Texture2D[1],
            sand = new Texture2D[1],
            wood = new Texture2D[1];
        Texture2D backdrop;
        SpriteBatch spriteBatch;
        Texture2D mapImage;
        Texture2D HealthBarBG, HealthBarFG;
        SoundEffect deathSFX;
        SpriteFont font;
        int screenHeight = 480;
        int screenWidth = 800;
        int mapWidth;
        int mapHeight;
        int frames;
        bool waterState = true; // which frame of water? 1 or 2?
        float speed = 4f, fallSpeed = 4f;
        bool spawned = false;
        List<block> blocks = new List<block>();
        List<character> characters = new List<character>();
        const float initalSpawnX = 30, initalSpawnY = 350;
        public float playerX = initalSpawnX;
        public float playerY = initalSpawnY;
        

        GameState gameState;

        public level(Texture2D map, Texture2D[] tileset, List<character> characters, Texture2D backdrop, Texture2D HealthBarBG, Texture2D HealthBarFG, SpriteFont font, SpriteBatch spriteBatch, SoundEffect deathSFX)
        {
            this.mapImage = map;
            this.backdrop = backdrop;
            this.spriteBatch = spriteBatch;
            this.mapHeight = get_map_height("pixel");
            this.mapWidth = get_map_width("pixel");
            this.water[0] = tileset[0];
            this.water[1] = tileset[1];
            this.grass[0] = tileset[2];
            this.ground[0] = tileset[3];
            this.sand[0] = tileset[4];
            this.stone[0] = tileset[5];
            this.brick[0] = tileset[6];
            this.characters = characters;
            this.HealthBarBG = HealthBarBG;
            this.HealthBarFG = HealthBarFG;
            this.font = font;
            this.deathSFX = deathSFX;
            

            int tileSize = 32;
            int k = 0, l = 0;
            for (float i = 0; i < mapWidth; i++)
            {
                for (float j = 0; j < mapHeight; j++)
                {
                    int type = get_tile_type((int)j, (int)i);
                    if (type == 1)
                        blocks.Add(new block(water, false, 0.5f, 0, (l * tileSize), (k * tileSize), spriteBatch));
                    else if (type == 2)
                        blocks.Add(new block(ground, true, 0.5f, 0, (l * tileSize), (k * tileSize), spriteBatch));
                    else if (type == 3)
                        blocks.Add(new block(grass, true, 0.5f, 0, (l * tileSize), (k * tileSize), spriteBatch));                    //else if(type == 254)
                    else if (type == 4)
                        blocks.Add(new block(stone, true, 0.5f, 0, (l * tileSize), (k * tileSize), spriteBatch));                    //else if(type == 254)
                    else if (type == 5)
                        blocks.Add(new block(sand, true, 0.5f, 0, (l * tileSize), (k * tileSize), spriteBatch));                    //else if(type == 254)
                    else if (type == 6)
                        blocks.Add(new block(brick, true, 0.5f, 0, (l * tileSize), (k * tileSize), spriteBatch));
                    else if (type == 99)
                        blocks.Add(new block(water, true, 0.5f, 1, (l * tileSize), (k * tileSize), spriteBatch));
                    else
                    {
                        blocks.Add(null);
                    }
                    k++;
                }
                l++;
                k = 0;
            }


        }

        public int get_map_width()
        {
            return get_map_width("tile");
        }

        public int get_map_height()
        {
            return get_map_height("tile");
        }

        public int get_map_width(string unit)
        {

            switch (unit)
            {
                case "pixel": return mapImage.Width;
                case "tile":
                default: return mapImage.Width * 32;
            }
        }

        public void set_state(GameState gameState)
        {
            this.gameState = gameState;
        }
        public GameState get_state()
        {
            return this.gameState;
        }

        public int get_map_height(string unit)
        {
            switch (unit)
            {
                case "pixel": return mapImage.Height;
                case "tile":
                default: return mapImage.Height * 32;
            }
        }

        public int get_tile_type(int x, int y)
        {
            // mapImage =  this.Content.Load<Texture2D>("Content/texture/sand");

            Color[] texColors = new Color[mapImage.Height * mapImage.Width];



            mapImage.GetData(texColors);

            //return mapImage.GetPixel(x, y).R;
            /*switch( mapImage.GetPixel(x,y).R )
            {
                case 237: return 1;
                default: return 0;
            }*/
            return texColors[((x * mapImage.Width) + y)].R;
        }

        private float get_boundary(string boundary)
        {
            float a = 0;
            switch (boundary)
            {
                case "top":
                    a = (float)(playerY - (((screenHeight / 2) - 32) / 64) - 1.5);
                    break;
                case "bottom":
                    a = (float)(playerY + (((screenHeight / 2) + 32) / 64) + 1.5);
                    break;
                case "left":
                    a = (float)(playerX - (((screenWidth / 2) - 32) / 64) - 1.5);
                    break;
                case "right":
                    a = (float)(playerX + (((screenWidth / 2) + 32) / 64) + 2.5);
                    break;
            }
            if (a < 0)
            {
                a = 0;
            }
            return a;
        }

        public void end_level()
        {
            switch (gameState)
            {
                case GameState.Level01:
                    this.gameState = GameState.Fmv04;
                    break;
            }
        }
        public void update()
        {
            KeyboardState state = Keyboard.GetState();
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
            Rectangle r = new Rectangle((int)playerX, (int)playerY, 25, 64);
            //find if player is on a block
            bool fall = true, jump = true, left = true, right = true ;
            int blockSize = 32, characterWidth=25, joshsSafeValue=56;

            if (playerY > (mapHeight * blockSize))
            {
                characters[0].hp--;
            }

            //DEATH HAPPENS HERE!
            if (characters[0].hp <= 0)
            {
                characters[0].lives--;
                playerX = initalSpawnX;
                playerY = initalSpawnY;
                characters[0].hp = 100;
                fallSpeed = speed;
                //stops spam loop of deathsfx!
                if(characters[0].lives>=0)
                    deathSFX.Play();

            }

            foreach (block b in blocks)
            {
                // Some weird stuff happens here. In theory, check for intersections and prevent the player moving into the block
                // repelling them out of it if required.
                if (b != null)
                {
                    if (r.Intersects(b.position))
                    {
                        if (b.damage == 1)
                        {
                            end_level();
                            
                        }
                        // Check for the intersection being at feet; if do, prevent falling.
                        if (r.Y + joshsSafeValue < b.y)
                        {
                            if (b.isSolid)
                                fall = false;
                            //else

                        }

                        // If the block is above, prevent jumping higher
                        if (r.Y > b.y + speed)
                        {
                            jump = false;
                            playerY += (speed/2);
                        }

                        // Same for the sides
                        if (r.X - blockSize < b.x && !(r.Y + joshsSafeValue < b.y))
                        {
                            left = false;
                        }
                        if (r.X + characterWidth > b.x && !(r.Y + joshsSafeValue < b.y))
                        {
                            if (state.IsKeyDown(Keys.Right) || (gamePadState.DPad.Right == ButtonState.Pressed))
                                if (b.isSolid)
                                    playerX  = b.position.Left - (characterWidth+3);
                        }
                        if (r.X + characterWidth > b.x && !(r.Y + joshsSafeValue < b.y))
                        {
                            right = false;
                            if (b.isSolid)
                                if (state.IsKeyDown(Keys.Left) || (gamePadState.DPad.Left == ButtonState.Pressed))
                                    playerX = b.position.Right +1;
                        }
                        if (fall)
                        {
                            if (!b.isSolid)
                            {
                                fallSpeed = (speed / 2);
                                left = false;
                                right = false;
                                
                            }
                            else
                                fallSpeed = speed;
                        }
                    }
                }
                string[] talk = new string[4];
                talk[0] = "Hello. =)";
                talk[1] = "";
                talk[2] = "";
                talk[3] = "";
                characters[0].talk(talk);
                characters[0].talk();
                characters[0].x = 388;
                characters[0].y = 208;
            }
            if (fall)
            {
                playerY += fallSpeed;
            }

            if (!fall)
            {
                frames = 0;
            }

            if (state.IsKeyDown(Keys.Up) || (gamePadState.DPad.Up == ButtonState.Pressed))
            {
                if (jump)
                {
                    frames++;
                    if (frames < ((blockSize*2)/speed))
                    {
                        playerY = playerY - (speed*2);
                    }
                    if(!fall) frames = 0;
                }
            }
            if (state.IsKeyDown(Keys.Left) || (gamePadState.DPad.Left == ButtonState.Pressed))
            {
                if (left)
                {
                    playerX = playerX - speed;
                    characters[0].walk_left();
                }
            }
            if (state.IsKeyDown(Keys.Right) || (gamePadState.DPad.Right == ButtonState.Pressed))
            {
                if (right)
                {
                    playerX = playerX + speed;
                    characters[0].walk_right();
                }
            }

            //Console.WriteLine(playerX + "," + playerY);
            foreach (block b in blocks)
            {
                if (b != null)
                {
                    b.update();
                }
            }

        }

        public void draw()
        {
            spriteBatch.Draw(backdrop, new Rectangle(0, 0, 800, 480), Color.White);
           
            // Draw the tiles
            foreach (block b in blocks)
            {
                if (b != null)
                {
                    b.draw(-(int)playerX+388 , -(int)playerY+208 );
                }
            }

            //spriteBatch.Draw(stone[0], new Rectangle(388,208, 25, 64), Color.Blue);
            bool first = true;
            foreach (character c in characters)
            {
                if (first)
                {
                    first = false;
                }
                c.draw();
                if (characters[0]==c)
                {
                    spriteBatch.Draw(HealthBarBG, new Rectangle(1, 1, 110, 35), Color.White);
                    spriteBatch.Draw(HealthBarFG, new Rectangle(6, 6, characters[0].hp, 25), Color.Red);
                    if (characters[0].lives > 0)
                    {
                        spriteBatch.DrawString(font, "Lives: " + characters[0].lives, new Vector2(27, 7), Color.Black);
                    }
                    else
                    {
                        spriteBatch.DrawString(font, "Game Over!", new Vector2(10, 7), Color.Black);
                        characters[0].hp = 0; 
                    }
                }
            }
        }
    }
}
